﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.ESB.Resolver;
using Microsoft.Practices.ESB.Resolver.BRE;
using Microsoft.Practices.ESB.Exception.Management;
using Microsoft.XLANGs.BaseTypes;
using System.Reflection;

namespace BizTalk.ESB.Extensions.Resolvers
{
    public class ServiceProxyRequestResolution
    {
        public String ServiceAction { get; set; }
        public String ServiceName { get; set; }
        public String ServiceType { get; set; }
        public Boolean IsRequestResponse { get; set; }
        public String TransformType { get; set; }
        public String MessageType { get; set; }
        public String DocumentSpecStrongName { get; set; }
    }

    public class ServiceProxyResponseResolution
    {
        public String MapInputType { get; set; }
        public Boolean ValidateResponse { get; set; }
        public String ValidateMethod { get; set; }
        public String ValidationPolicyName { get; set; }
        public String ValidationPolicyVersion { get; set; }
        public String ValidationXsdType { get; set; }
        public String ValidationTrace { get; set; }
        public String ValidationDocType { get; set; }
        public String TransformType { get; set; }
        public String MessageType { get; set; }
        public String DocumentSpecStrongName { get; set; }
        public bool MergeContext { get; set; }
    }

    public class ServiceProxyResolutionManager
    {
        public static BRE CreateResolverDescriptor(String config, String resolver)
        {
            BRE breWrapper;

            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (resolver == null)
            {
                throw new ArgumentNullException("resolver");
            }

            Dictionary<String, String> facts = null;
            try
            {
                BRE breTemp = new BRE();
                breTemp.useMsg = false;
                facts = ResolverMgr.GetFacts(config, resolver);
                breTemp.policy = ResolverMgr.GetConfigValue(facts, true, "policy");
                breTemp.version = ResolverMgr.GetConfigValue(facts, false, "version");
                Boolean useMessage, recognizeMessage;
                breTemp.useMsgSpecified = Boolean.TryParse(
                    ResolverMgr.GetConfigValue(facts, false, "useMsg")
                    , out useMessage);
                breTemp.recognizeMessageFormatSpecified = Boolean.TryParse(
                    ResolverMgr.GetConfigValue(facts, false, "recognizeMessageFormat")
                    , out recognizeMessage);
                breTemp.useMsg = useMessage;
                breTemp.recognizeMessageFormat = recognizeMessage;

                breWrapper = breTemp;
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (facts != null)
                {
                    facts.Clear();
                    facts = null;
                }
            }

            return breWrapper;
        }

        public static void SetResolverDictionary(ServiceProxyRequestResolution resolution, Dictionary<String, String> dictionary)
        {
            try
            {
                dictionary.Add("Resolver.IsRequestResponse", resolution.IsRequestResponse.ToString());
                dictionary.Add("Resolver.ServiceAction", resolution.ServiceAction);
                dictionary.Add("Resolver.ServiceName", resolution.ServiceName);
                dictionary.Add("Resolver.ServiceType", resolution.ServiceType);
                dictionary.Add("Resolver.TransformType", resolution.TransformType);
            }
            catch { }
        }

        public static void SetResolverDictionary(ServiceProxyResponseResolution resolution, Dictionary<String, String> dictionary)
        {
            try
            {
                dictionary.Add("Resolver.MapInputType", resolution.MapInputType);
                dictionary.Add("Resolver.TransformType", resolution.TransformType);
                dictionary.Add("Resolver.ValidateMethod", resolution.ValidateMethod);
                dictionary.Add("Resolver.ValidateFlag", resolution.ValidateResponse.ToString());
                dictionary.Add("Resolver.ValidationPolicyName", resolution.ValidationPolicyName);
                dictionary.Add("Resolver.ValidationPolicyVersion", resolution.ValidationPolicyVersion);
                dictionary.Add("Resolver.ValidationXsdType", resolution.ValidationXsdType);
                dictionary.Add("Resolver.ValidationTrace", resolution.ValidationTrace);
                dictionary.Add("Resolver.ValidationDocType", resolution.ValidationDocType);
                dictionary.Add("Resolver.MergeContext", resolution.MergeContext.ToString());
            }
            catch { }
        }

        public static void SetContext(ServiceProxyRequestResolution resolution, XLANGMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (resolution == null)
            {
                throw new ArgumentNullException("resolution");
            }
            try
            {
                resolution.MessageType = ((String)ServiceProxyResolutionManager.GetMsgProperty(message
                    , typeof(BTS.MessageType))) ?? String.Empty;
                resolution.DocumentSpecStrongName = ((String)ServiceProxyResolutionManager.GetMsgProperty(message
                    , typeof(BTS.SchemaStrongName))) ?? String.Empty;
                if (String.IsNullOrEmpty(resolution.DocumentSpecStrongName) == false)
                {
                    Int32 index = resolution.DocumentSpecStrongName.IndexOf(",", StringComparison.CurrentCultureIgnoreCase);
                    if ((index > 0) && (index < resolution.DocumentSpecStrongName.Length))
                    {
                        resolution.DocumentSpecStrongName = resolution.DocumentSpecStrongName.Substring(0, index);
                    }
                }
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
        }

        public static void SetContext(ServiceProxyResponseResolution resolution, XLANGMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (resolution == null)
            {
                throw new ArgumentNullException("resolution");
            }
            try
            {
                resolution.MessageType = ((String)ServiceProxyResolutionManager.GetMsgProperty(message
                    , typeof(BTS.MessageType))) ?? String.Empty;
                resolution.DocumentSpecStrongName = ((String)ServiceProxyResolutionManager.GetMsgProperty(message
                    , typeof(BTS.SchemaStrongName))) ?? String.Empty;
                if (String.IsNullOrEmpty(resolution.DocumentSpecStrongName) == false)
                {
                    Int32 index = resolution.DocumentSpecStrongName.IndexOf(",", StringComparison.CurrentCultureIgnoreCase);
                    if ((index > 0) && (index < resolution.DocumentSpecStrongName.Length))
                    {
                        resolution.DocumentSpecStrongName = resolution.DocumentSpecStrongName.Substring(0, index);
                    }
                }
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
        }

        private static Object GetMsgProperty(XLANGMessage message, Type property)
        {
            Object prop;
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }
            if (property == null)
            {
                throw new ArgumentNullException("property");
            }
            Object PropertyValue = null;
            try
            {
                PropertyValue = message.GetPropertyValue(property);
                prop = PropertyValue;
            }
            catch (Exception e)
            {
                EventLogger.Write(MethodBase.GetCurrentMethod(), e);
                throw;
            }
            finally
            {
                if (PropertyValue != null)
                {
                    PropertyValue = null;
                }
            }
            return prop;
        }
    }
}
